#include "head.h"

// 定义用来通知子进程退出信息的管道
int pipe_fd[2];

void func(int num){
    //printf("收到2号信号\n");
    write(pipe_fd[1], "1", 1);
}


int main(int argc, char *argv[])
{
    // 初始化管道
    pipe(pipe_fd);

    // 注册2号信号
    signal(2, func);

    // 那三个子进程的状态结构体数组
    status_t list[LIST_SIZE];
    
    // 搞一个函数,来启动子进程们
    initPool(list, LIST_SIZE);

    // 搞一个函数,创建那个专门用来监听的socket
    int socket_fd;
    initSocket(&socket_fd, "192.168.244.135", "8080");

    // 创建epoll对象
    int epoll_fd = epoll_create(1);
    ERROR_CHECK(epoll_fd, -1, "epoll_create");
    // 搞一个函数,把socket_fd放到epoll中监听,为了监听有没有新连接进来
    addEpoll(epoll_fd, socket_fd);

    // 再下面需要监听子线程对应的本地socket们
    // 因为父进程就是监听有没有连接过来或者有没有数据过来
    // 所以父进程还要监听那三个子进程对应的本地socket
    for(int i=0; i<LIST_SIZE; i++){
        // 把那三个进程的本地socket也都放在里面
        addEpoll(epoll_fd, list[i].local_socket);
    }

    // 把用于进程退出的管道读端也加入监听
    addEpoll(epoll_fd, pipe_fd[0]);

    // 父进程开始监听
    while(1){
        // 创建socket监听队列
        struct epoll_event events[10];
        int epoll_num = epoll_wait(epoll_fd, events, 10, -1);
        //ERROR_CHECK(epoll_num, -1, "epoll_wait");
        
        printf("epoll over \n");
        // 队列里会放着已经等待着处理的socket,下面就把他们处理一下
        // 一共就两种可能,主进程就干俩活 1.新的连接进来 2.子进程处理完了
        for(int i=0; i<epoll_num; i++){
            // fd是监听到的文件描述符
            int fd = events[i].data.fd;
            
            // 0.进程退出的逻辑
            if(fd == pipe_fd[0]){
                // 有写就有读
                char buf[60] = {0};
                read(pipe_fd[0], buf, sizeof(buf));
                // 通过本地socket给子进程发信息让子进程退出
                // 给localSendMsg函数再加一个int flag 以标记是否将子进程退出
                
                for(int j=0; j<LIST_SIZE; j++){
                    localSendMsg(list[j].local_socket, 1, -1);
                }

                // 等待三个子进程退出
                for(int k=0; k<LIST_SIZE; k++){
                    wait(NULL);
                }

                // TODO 假装清理资源

                // 最后父进程退出
                exit(0);
            }

            if(fd == socket_fd){
                // 1.有新的连接进来,返回那个进来的文件描述符
                int net_fd = accept(socket_fd, NULL, NULL);
                // 交给空闲线程
                toList(list, LIST_SIZE, net_fd);
                // 关闭net_fd
                // 因为已经给了子进程,只是把主进程的socket干掉,减少引用计数
                close(net_fd);
            }else{
                // 2.有子进程处理完回来报告
                for(int j=0; j<LIST_SIZE; j++){
                    // 把监听到的进程和子进程数组中的子进程进行比较
                    if(list[j].local_socket == fd){
                        // 定位到子进程数组中的某一个
                        // 为了避免缓冲区有数据但退出,先把socket缓冲区读空
                        char buf[60];
                        recv(list[j].local_socket, buf, sizeof(buf), 0);
                        // 把这个子进程状态由忙改为闲
                        list[j].status = FREE;
                        break;
                    }
                }
            }

        }
    }

    return 0;
}
